/**************************
* @Summary
* @Author 20009200303 赵传博
* @Date 2022/3/31
*****************************/

#include "Date.h"
#include <cmath>

Date::Date(int year, int month, int day) {
    this->year = year;
    this->month = month;
    this->day = day;
    this->isLeap = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}

void Date::printMe() {
    cout << year << '-' << month << '-' << day;
}

Date Date::plusOneDay() {
    Date newDate(year, month, day);
    if(month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12){
        if(day < 31){
            newDate.setDay(day + 1);
        }else{
            if(month == 12){
                newDate.setYear(year + 1);
                newDate.setMonth(1);
                newDate.setDay(1);
            }else{
                newDate.setMonth(month + 1);
                newDate.setDay(1);
            }
        }
    }else if(month == 4 || month == 6 || month == 9 || month == 11){
        if(day < 30){
            newDate.setDay(day + 1);
        }else{
            newDate.setMonth(month + 1);
            newDate.setDay(1);
        }
    }else{
        if(!isLeap){
            if(day < 28){
                newDate.setDay(day + 1);
            }else{
                newDate.setMonth(month + 1);
                newDate.setDay(1);
            }
        }else{
            if(day < 29){
                newDate.setDay(day + 1);
            }else{
                newDate.setMonth(month + 1);
                newDate.setDay(1);
            }
        }
    }
    return newDate;
}

Date Date::firstMonthday() {
    Date newDate(year, month, day);
    int todayIs = this->date2Calendar();
    if(todayIs != 0){
        for(int i = 0; i < 7 - todayIs + 1; ++i){
            newDate = newDate.plusOneDay();
        }
    }else{
        newDate = newDate.plusOneDay();
    }
    return newDate;
}

int Date::date2Calendar() {
    // 按照2021年3月28日是周日，计算date对应是周几  (不推荐选择这天做参考，选个整的日期更好推算)
    // 计算给定日期距2021年3月28日有多少天
    /*
     *  比如2022-3-31
     *  首先，2022>2021,2022不<2022
     *  那么2021-3-28到31号还有3天，再加上到2021-12-31号所有的天数
     */
    // 如果日期大于2021年03月28日  mod 7 ，余数是0则是周日，余数是1则是周一，以此类推，余数6则周六
    // 如果日期小于2021年03月28日  mod 7 之后是距离周日还有几天  因此是 （7 - countDay%7）%7
            //最后多%个7是因为距离周日为0和7天都是周日，最后都应该处理成0
                //即(7-0) % 7 == (7-7)%7 == 0
    // 跨一个闰年加366，跨一个平年加365天；跨一个1，3，5，7，8，10，12月加31天；跨一个4，6，9，11加30天；跨平年2月加27天,跨闰年2月加28天
    int countDay = 0;
    if(year > 2021) {
        // 多了多少个整年
        for(int i = 2022; i < year; i++) {
            if((i % 4 == 0 && i % 100 != 0) || i % 400 == 0) {
                countDay += 366;
            }
            else {
                countDay += 365;
            }
        }
        // 补齐到当年 3    5    7    8   10    12   4      6    9    11（补到2021年末）
        countDay += 3 + 31 + 31 + 31 + 31 + 31 + 30  + 30 + 30 + 30;
        // 当年有几个整月
        for(int i = 1; i < month; i++) {
            if(i==1 || i==3 || i==5 || i==7 || i==8 || i==10 || i==12) {
                countDay += 31;
            }
            else if(i==4 || i==6 || i==9 || i==11) {
                countDay += 30;
            }
            else {
                if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
                    countDay += 29;
                }
                else {
                    countDay += 28;
                }
            }
        }
        //补齐到当天
        countDay += day;
        return countDay%7;
    }
    else if(year < 2021) {
        // 少了多少个整年
        for(int i = 2020; i > year; i--) {
            if(((i + 1) % 4 == 0 && (i + 1) % 100 != 0) || (i + 1) % 400 == 0) {
                countDay += 366;
            }
            else {
                countDay += 365;
            }
        }
        // 补齐到当年
        if(((year+1) % 4 == 0 && (year+1) % 100 != 0) || (year+1) % 400 == 0) {
            countDay += 31 + 29 + 28;
        }
        else {
            countDay += 31 + 28 + 28;
        }
        // 当年有几个整月
        for(int i = month; i <= 12; i++) {
            if(i==1 || i==3 || i==5 || i==7 || i==8 || i==10 || i==12) {
                countDay += 31;
            }
            else if(i==4 || i==6 || i==9 || i==11) {
                countDay += 30;
            }
            else {
                if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
                    countDay += 29;
                }
                else {
                    countDay += 28;
                }
            }
        }
        //补齐到当天
        countDay -= day;
        return (7 - (countDay%7))%7;
    }
    else {
        int day2021 = 0;
        for(int i = 1; i < month; i++) {
            if(i==1 || i==3 || i==5 || i==7 || i==8 || i==10 || i==12) {
                day2021 += 31;
            }
            else if(i==4 || i==6 || i==9 || i==11) {
                day2021 += 30;
            }
            else {
                day2021 += 28;
            }
        }
        day2021 += day;
        countDay += abs(day2021 - (31 + 28 + 28));
        if(month > 3 || ((month == 3) && (day > 28))) {
            return countDay%7;
        }
        else {
            return (7 - (countDay%7))%7;
        }
    }
}

Date Date::plusOneYear() {
    Date newDate(year + 1, month, day);
    return newDate;
}

Date Date::plusOneMonth() {
    Date newDate(year, month, day);
    int totalDays;
    if(month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) totalDays = 31;
    else if(month == 4 || month == 6 || month == 9 || month == 11) totalDays = 30;
    else if(!isLeap) totalDays = 28; else totalDays = 29;
    for(int i = 0; i < totalDays ; ++i){
        newDate = newDate.plusOneDay();
    }
    return newDate;
}

void Date::setYear(int year) {
    this->year = year;
}

void Date::setMonth(int month) {
    this->month = month;
}

void Date::setDay(int day) {
    this->day = day;
}

ostream &operator<<(ostream &os, const Date &date) {
    os << date.year << '-' << date.month << '-' << date.day;
    return os;
}
